//
//  FLOpenCVTool.m
//  faceLooker
//
//  Created by yww on 2019/1/3.
//  Copyright © 2019年 yww. All rights reserved.
//

#import "FLOpenCVTool.h"
#include <stdio.h>
#include <iostream>

//using namespace std;
using namespace cv;
@implementation FLOpenCVTool
// 用来保存唯一的单例对象
static id _instance;
+ (instancetype)sharedInstance{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

+ (id)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}

- (id)copyWithZone:(NSZone *)zone{
    return _instance;
}

//  方框滤波
- (UIImage *)ImageToBoxFilter:(UIImage *)image{
    Mat mat_image_src;
    UIImageToMat(image, mat_image_src);
    Mat mat_image_out;
    boxFilter(mat_image_src, mat_image_out, -1, cv::Size(15,15));
    return MatToUIImage(mat_image_out);
    /*
     boxFilter(参数一,参数二,参数三,参数四,参数五,参数六,参数七)
     第一个参数，InputArray类型的src，输入图像，即源图像，填Mat类的对象即可。该函数对通道是独立处理的，且可以处理任意通道数的图片，但需要注意，待处理的图片深度应该为CV_8U, CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
     第二个参数，OutputArray类型的dst，即目标图像，需要和源图片有一样的尺寸和类型。
     第三个参数，int类型的ddepth，输出图像的深度，-1代表使用原图深度，即src.depth()。
     第四个参数，Size类型（对Size类型稍后有讲解）的ksize，内核的大小。一般这样写Size( w,h )来表示内核的大小( 其中，w 为像素宽度， h为像素高度)。Size（3,3）就表示3x3的核大小，Size（5,5）就表示5x5的核大小
     第五个参数，Point类型的anchor，表示锚点（即被平滑的那个点），注意他有默认值Point(-1,-1)。如果这个点坐标是负值的话，就表示取核的中心为锚点，所以默认值Point(-1,-1)表示这个锚点在核的中心。
     第六个参数，bool类型的normalize，默认值为true，一个标识符，表示内核是否被其区域归一化（normalized）了。
     第七个参数，int类型的borderType，用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT，我们一般不去管它。
     */
}

//  高斯模糊
- (UIImage *)ImageToGaussianBlur:(UIImage *)image{
    Mat mat_image_src;
    UIImageToMat(image, mat_image_src);
    Mat mat_image_out;
    GaussianBlur(mat_image_src, mat_image_out, cv::Size(21,21), 0,0);
    return MatToUIImage(mat_image_out);
    /*
     GaussianBlur(参数一,参数二,参数三,参数四,参数五,参数六)
     第一个参数，InputArray类型的src，输入图像，即源图像，填Mat类的对象即可。它可以是单独的任意通道数的图片，但需要注意，图片深度应该为CV_8U,CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
     第二个参数，OutputArray类型的dst，即目标图像，需要和源图片有一样的尺寸和类型。比如可以用Mat::Clone，以源图片为模板，来初始化得到如假包换的目标图。
     第三个参数，Size类型的ksize高斯内核的大小。其中ksize.width和ksize.height可以不同，但他们都必须为正数和奇数。或者，它们可以是零的，它们都是由sigma计算而来。
     第四个参数，double类型的sigmaX，表示高斯核函数在X方向的的标准偏差。
     第五个参数，double类型的sigmaY，表示高斯核函数在Y方向的的标准偏差。若sigmaY为零，就将它设为sigmaX，如果sigmaX和sigmaY都是0，那么就由ksize.width和ksize.height计算出来。
     为了结果的正确性着想，最好是把第三个参数Size，第四个参数sigmaX和第五个参数sigmaY全部指定到。
     第六个参数，int类型的borderType，用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT，我们一般不去管它。
     */
}

// 中值滤波
- (UIImage *)ImageToMedianFilter:(UIImage *)image{
    Mat mat_image_src;
    UIImageToMat(image, mat_image_src);
    Mat mat_image_out;
    medianBlur(mat_image_src, mat_image_out, 7);
    return MatToUIImage(mat_image_out);
    /*
     medianBlur(参数一,参数二,参数三)
     第一个参数，InputArray类型的src，输入图像，即源图像，填Mat类的对象即可。该函数对通道是独立处理的，且可以处理任意通道数的图片，但需要注意，待处理的图片深度应该为CV_8U, CV_16U, CV_16S, CV_32F 以及 CV_64F之一。
     第二个参数，OutputArray类型的dst，即目标图像，需要和源图片有一样的尺寸和类型。
     第三个参数，类型为ksize 第三个参数 孔径的尺寸  必须是大于1的奇数  3 5 7 9 11
     */
}

// 双边滤波
- (UIImage *)ImageTobilateraFilter:(UIImage *)image{
    Mat mat_image_src,gray;
    Mat mat_image_out;
    UIImageToMat(image, mat_image_src);
//    cv::cvtColor(mat_image_src, gray,CV_BGR2BGRA);
    cvtColor(mat_image_src, gray, CV_RGBA2RGB, 3);
    bilateralFilter(gray, mat_image_out,15, 50, 35);
    return MatToUIImage(mat_image_out);
    /*
     bilateralFilter(参数一,参数二,参数三,参数四,参数五)
     参数一，MAT类型，原图
     参数二，即目标图像，需要和源图片有一样的尺寸和类型
     */
}

//均值滤波
- (UIImage *)ImageToblurFilter:(UIImage *)image{
    Mat mat_image_src;
    UIImageToMat(image, mat_image_src);
    Mat mat_image_out;
    blur(mat_image_src, mat_image_out, cv::Size(15,15));
    return MatToUIImage(mat_image_out);
    //参数同方框滤波 kesiter la
    //方片滤波。真空像是 可你们老板
}
@end
